package com.efrei.schoolmanager.controlers;

import java.util.Date;
import java.util.List;
import java.util.Set;

import org.hibernate.HibernateException;
import org.hibernate.Session;

import com.efrei.schoolmanager.exceptions.LogicException;
import com.efrei.schoolmanager.model.hibernate.dao.ClasseDAO;
import com.efrei.schoolmanager.model.hibernate.dao.EleveDAO;
import com.efrei.schoolmanager.model.hibernate.dao.EtablissementDAO;
import com.efrei.schoolmanager.model.hibernate.dao.MedecinDAO;
import com.efrei.schoolmanager.model.hibernate.dao.PaysDAO;
import com.efrei.schoolmanager.model.hibernate.dao.VilleDAO;
import com.efrei.schoolmanager.model.obj.Classe;
import com.efrei.schoolmanager.model.obj.Eleve;
import com.efrei.schoolmanager.model.obj.Etablissement;
import com.efrei.schoolmanager.model.obj.Medecin;
import com.efrei.schoolmanager.model.obj.Pays;
import com.efrei.schoolmanager.model.obj.Responsable;
import com.efrei.schoolmanager.model.obj.Ville;
import com.efrei.schoolmanager.tools.Tools;
import com.efrei.schoolmanager.tools.Verifs;

/**
 * edit l'eleve donné dans le constructeur. null pour nouvel eleve
 * 
 * @see ControleurTransactionnel
 */
public class ControleurEleve extends ControleurTransactionnel {
	// private ModeleAjoutEleve mae;

	// les dao
	private final EleveDAO eleveDao;
	private final VilleDAO villeDao;
	private final PaysDAO paysDao;
	private final MedecinDAO medecinDao;
	private final ClasseDAO classeDao;
	private final EtablissementDAO etablissementDao;
	// les données
	private Eleve eleve;
	private Classe classeCourante;
	private List<Pays> listPays;
	private List<Medecin> listMedecins;
	private List<Classe> listClasse;
	private List<Etablissement> listEtablissements;
	/**
	 * indique si l'eleve est nouveau ou doit etre modifié
	 */
	private boolean isNew;

	/**
	 * edit l'eleve donné dans le constructeur.
	 * 
	 * @param eleve
	 *            null pour nouvel eleve
	 * @throws LogicException
	 * @throws HibernateException
	 */
	public ControleurEleve(Eleve eleve) throws HibernateException,
			LogicException {
		super();
		// instanciation des DAO
		Session session = getSession();
		eleveDao = new EleveDAO(session);
		villeDao = new VilleDAO(session);
		paysDao = new PaysDAO(session);
		medecinDao = new MedecinDAO(session);
		classeDao = new ClasseDAO(session);
		etablissementDao = new EtablissementDAO(session);

		// reference a l'eleve modifié pour la session
		if (eleve == null) {
			this.isNew = true;
			this.eleve = new Eleve();
		} else {
			this.isNew = false;
			// pour ne pas avoir de probleme, venant d'une autre session
			eleveDao.reattachToSession(eleve);
			this.eleve = eleve;
		}
	}

	/*
	 * RESPONSABLE
	 */

	/**
	 * ajoute un responsable. Si l'eleve doit être edité, alors le donner en
	 * argument, sinon null en attendant le futur nouvel eleve.
	 * 
	 * @param nom
	 * @param prenom
	 * @param rue
	 * @param codePostal
	 * @param nomVille
	 * @param paysVille
	 * @param telephoneFixe
	 * @param telephoneMobile
	 * @param telephoneProfessionnel
	 * @param email
	 * @throws LogicException
	 */
	public void ajoutResponsable(String nom, String prenom, String rue,
			String codePostal, String nomVille, Pays paysVille,
			String telephoneFixe, String telephoneMobile,
			String telephoneProfessionnel, String email) throws LogicException {
		Responsable.check(nom, prenom, rue, telephoneFixe, telephoneMobile,
				telephoneProfessionnel, email);
		Ville ville = villeDao.getOrCreateVille(codePostal.trim(),
				nomVille.trim(), paysVille);

		Responsable responsable = new Responsable(nom.trim(), prenom.trim(),
				rue.trim(), ville, telephoneFixe.trim(),
				telephoneMobile.trim(), telephoneProfessionnel.trim(),
				email.trim());
		eleve.getResponsablesLegaux().add(responsable);
	}

	/**
	 * edit le responsable donné en parametre. Il est lié à l'eleve donc sera
	 * edité en même temps que lui
	 * 
	 * @param responsable
	 * @param nom
	 * @param prenom
	 * @param rue
	 * @param codePostal
	 * @param nomVille
	 * @param paysVille
	 * @param telephoneFixe
	 * @param telephoneMobile
	 * @param telephoneProfessionnel
	 * @param email
	 * @throws LogicException
	 */
	public void editResponsable(Responsable responsable, String nom,
			String prenom, String rue, String codePostal, String nomVille,
			Pays paysVille, String telephoneFixe, String telephoneMobile,
			String telephoneProfessionnel, String email) throws LogicException {
		Responsable.check(nom, prenom, rue, telephoneFixe, telephoneMobile,
				telephoneProfessionnel, email);
		Ville ville = villeDao
				.getOrCreateVille(codePostal, nomVille, paysVille);

		responsable.setNom(nom.trim());
		responsable.setPrenom(prenom.trim());
		responsable.setRue(rue.trim());
		responsable.setVille(ville);
		responsable.setTelephoneFixe(telephoneFixe.trim());
		responsable.setTelephoneMobile(telephoneMobile.trim());
		responsable.setTelephoneProfessionnel(telephoneProfessionnel.trim());
		responsable.setEmail(email.trim());
	}

	/**
	 * detruit un responsable de l'eleve
	 * 
	 * @param responsable
	 * @throws LogicException
	 */
	public void removeResponsable(Responsable responsable)
			throws LogicException {
		if (responsable == null
				|| !eleve.getResponsablesLegaux().contains(responsable))
			throw new LogicException("Responsable pas affilié à l'eleve");
		eleve.getResponsablesLegaux().remove(responsable);
	}

	/*
	 * MEDECIN
	 */

	/**
	 * ajoute le medecin
	 * 
	 * @param nom
	 * @param prenom
	 * @param telephoneFixe
	 * @param email
	 * @param rue
	 * @param codePostal
	 * @param nomVille
	 * @param paysVille
	 * @throws LogicException
	 */
	public Medecin ajoutMedecin(String nom, String prenom,
			String telephoneFixe, String email, String rue, String codePostal,
			String nomVille, Pays paysVille) throws LogicException {
		Medecin.check(nom, prenom, telephoneFixe, email, rue);
		Ville ville = villeDao
				.getOrCreateVille(codePostal, nomVille, paysVille);

		// ajout a la liste et à l'eleve
		Medecin medecin = new Medecin(nom.trim(), prenom.trim(),
				telephoneFixe.trim(), email.trim(), rue.trim(), ville);
		listMedecins.add(medecin);
		return medecin;
	}

	/**
	 * edit le medecin donné en parametre
	 * 
	 * @param medecin
	 * @param nom
	 * @param prenom
	 * @param telephoneFixe
	 * @param email
	 * @param rue
	 * @param codePostal
	 * @param nomVille
	 * @param paysVille
	 * @throws LogicException
	 */
	public void editMedecin(Medecin medecin, String nom, String prenom,
			String telephoneFixe, String email, String rue, String codePostal,
			String nomVille, Pays paysVille) throws LogicException {
		Medecin.check(nom, prenom, telephoneFixe, email, rue);
		Ville ville = villeDao
				.getOrCreateVille(codePostal, nomVille, paysVille);

		// sera modifié en base en même temps que l'eleve
		medecin.setNom(nom.trim());
		medecin.setPrenom(prenom.trim());
		medecin.setRue(rue.trim());
		medecin.setVille(ville);
		medecin.setTelephoneFixe(telephoneFixe.trim());
		medecin.setEmail(email.trim());
	}

	/**
	 * detruit un medecin de la base
	 * 
	 * @param responsable
	 * @throws LogicException
	 */
	public void removeMedecin(Medecin medecin) throws LogicException {
		if (medecin == null || !getMedecins().contains(medecin))
			throw new LogicException("Medecin inconnu !");
		// destruction de la liste et de la base
		medecinDao.delete(medecin);
		getMedecins().remove(medecin);
	}

	/*
	 * ETABLISSEMENT
	 */

	/**
	 * ajoute le nouvel etablissement
	 * 
	 * @param nom
	 * @param rue
	 * @param ville
	 * @param telephoneFixe
	 * @return
	 * @throws LogicException
	 */
	public Etablissement ajoutEtablissement(String nom, String rue,
			String codePostal, String nomVille, Pays paysVille,
			String telephoneFixe) throws LogicException {
		Etablissement.check(nom, rue, telephoneFixe);
		Ville ville = villeDao
				.getOrCreateVille(codePostal, nomVille, paysVille);

		Etablissement etablissement = new Etablissement(nom.trim(), rue.trim(),
				ville, telephoneFixe.trim());
		listEtablissements.add(etablissement);
		return etablissement;
	}

	/**
	 * edit l'etablissement donné en parametre
	 * 
	 * @param etablissement
	 * @param nom
	 * @param rue
	 * @param codePostal
	 * @param nomVille
	 * @param paysVille
	 * @param telephoneFixe
	 * @throws LogicException
	 */
	public void editEtablissement(Etablissement etablissement, String nom,
			String rue, String codePostal, String nomVille, Pays paysVille,
			String telephoneFixe) throws LogicException {
		Etablissement.check(nom, rue, telephoneFixe);
		Ville ville = villeDao
				.getOrCreateVille(codePostal, nomVille, paysVille);

		etablissement.setNom(nomVille.trim());
		etablissement.setRue(rue.trim());
		etablissement.setTelephoneFixe(telephoneFixe.trim());
		etablissement.setVille(ville);
	}

	/*
	 * ELEVE
	 */

	/**
	 * ajoute ou edite un eleve selon ce qui aura été donné au constructeur
	 * 
	 * @throws LogicException
	 * @throws IllegalArgumentException
	 *             pour des mauvaises chaines
	 * @throws NumberFormatException
	 *             pour les parse de date invalides
	 */
	public void editEleve(String matricule, String nom, String prenom,
			String dateNaissance, String codePostalVilleNaissance,
			String nomVilleNaissance, Pays paysVilleNaissance,
			Pays nationalite, String sexe, String rue,
			String codePostalLieuResidence, String nomLieuResidence,
			Pays paysResidence, String email, String dateInscription,
			Etablissement etablissementPrecedent, String photo,
			String telDomicile, String telMobile1, String telMobile2,
			Medecin medecinTraitant, String remarquesMedicales,
			String vaccinations, String allergies) throws LogicException {
		// pour factoriser l'action et eviter les trim incessants
		affectEleve(matricule.trim(), nom.trim(), prenom.trim(),
				dateNaissance.trim(), codePostalVilleNaissance.trim(),
				nomVilleNaissance.trim(), paysVilleNaissance, nationalite,
				sexe.trim(), rue.trim(), codePostalLieuResidence.trim(),
				nomLieuResidence.trim(), paysResidence, email.trim(),
				dateInscription.trim(), etablissementPrecedent, photo,
				telDomicile.trim(), telMobile1.trim(), telMobile2.trim(),
				medecinTraitant, remarquesMedicales.trim(),
				vaccinations.trim(), allergies.trim());
	}

	private void affectEleve(String matricule, String nom, String prenom,
			String strDateNaissance, String codePostalVilleNaissance,
			String nomVilleNaissance, Pays paysVilleNaissance,
			Pays nationalite, String sexe, String rue,
			String codePostalLieuResidence, String nomLieuResidence,
			Pays paysResidence, String email, String strDateInscription,
			Etablissement etablissementPrecedent, String photo,
			String telDomicile, String telMobile1, String telMobile2,
			Medecin medecinTraitant, String remarquesMedicales,
			String vaccinations, String allergies) throws LogicException {
		Eleve.check(matricule, nom, prenom, sexe, rue, email, photo,
				telDomicile, telMobile1, telMobile2, remarquesMedicales,
				vaccinations, allergies);
		// pointeurs null
		if (nationalite == null)
			throw new LogicException("nationalite invalide");
		if (paysResidence == null)
			throw new LogicException("pays residence invalide");
		if (etablissementPrecedent == null)
			throw new LogicException("etablissement précedent invalide");
		if (medecinTraitant == null)
			throw new LogicException("medecin traitant invalide");

		// forme par défaut year/month/day => tableau de la forme day/month/year
		Date dateNaissance = Tools.getDate(strDateNaissance,
				Tools.SEPARATEUR_FR);
		Date dateInscription = Tools.getDate(strDateInscription,
				Tools.SEPARATEUR_FR);

		// Ville.checkVille(codePostalVilleNaissance, nomVilleNaissance,
		// nationalite);
		// Ville.checkVille(codePostalLieuResidence, nomLieuResidence,
		// paysResidence);
		Verifs.checkString(codePostalVilleNaissance,
				"code postal de la ville de naissance invalide");
		Verifs.checkString(nomVilleNaissance,
				"nom de la ville de naissance invalide");
		Verifs.checkString(codePostalLieuResidence,
				"code postal du lieu de résidence invalide");
		Verifs.checkString(nomLieuResidence,
				"ville du lieu de résidence invalide");
		// et construction
		Ville villeNaissance = villeDao
				.getOrCreateVille(codePostalVilleNaissance, nomVilleNaissance,
						paysVilleNaissance);
		Ville villeResidence = villeDao.getOrCreateVille(
				codePostalLieuResidence, nomLieuResidence, paysResidence);

		// remplissage des différents champs pour l'eleve
		eleve.setMatricule(matricule);
		eleve.setNom(nom);
		eleve.setPrenom(prenom);
		eleve.setDateNaissance(dateNaissance);
		eleve.setVilleNaissance(villeNaissance);
		eleve.setDateInscription(dateInscription);
		eleve.setNationalite(nationalite);
		eleve.setSexe(sexe);
		eleve.setRue(rue);
		eleve.setVille(villeResidence);
		eleve.setEmail(email);
		eleve.setDateInscription(dateInscription);
		eleve.setEtablissementPrecedent(etablissementPrecedent);
		eleve.setPhoto(photo);
		eleve.setTelDomicile(telDomicile);
		eleve.setTelMobile1(telMobile1);
		eleve.setTelMobile2(telMobile2);
		eleve.setMedecinTraitant(medecinTraitant);
		eleve.setRemarquesMedicales(remarquesMedicales);
		eleve.setVaccinations(vaccinations);
		eleve.setAllergies(allergies);
	}

	@Override
	public void validAndQuit() throws LogicException {
		Session session = getSession();

		if (classeCourante == null)
			throw new LogicException("Classe non renseignée");
		eleve.getClasses().add(classeCourante);

		if (listMedecins != null)
			for (Medecin medecin : listMedecins) {
				session.saveOrUpdate(medecin);
			}
		if (listEtablissements != null)
			for (Etablissement etablissement : listEtablissements) {
				session.saveOrUpdate(etablissement);
			}
		// valide l'eleve
		for (Responsable responsable : eleve.getResponsablesLegaux())
			session.saveOrUpdate(responsable);
		eleveDao.saveOrUpdate(eleve);
		super.validAndQuit();
	}

	/**
	 * retourne toujours la même liste de Pays à chaque appel
	 * 
	 * @return la liste des pays connus
	 */
	public List<Pays> getPays() {
		if (listPays == null)
			listPays = paysDao.getPays();
		return listPays;
	}

	/**
	 * retourne toujours la même liste de Medecins à chaque appel
	 * 
	 * @return liste des medecins connus
	 */
	public List<Medecin> getMedecins() {
		if (listMedecins == null)
			listMedecins = medecinDao.getMedecins();
		return listMedecins;
	}

	public List<Classe> getClasses() {
		if (listClasse == null)
			listClasse = classeDao.getClasses();
		return listClasse;
	}

	public Set<Responsable> getResponsables() {
		return eleve.getResponsablesLegaux();
	}

	public List<Etablissement> getEtablissements() {
		if (listEtablissements == null)
			listEtablissements = etablissementDao.getEtablissements();
		return listEtablissements;
	}

	/**
	 * @return l'eleve sur lequel on travaille
	 */
	public Eleve getEleve() {
		return eleve;
	}

	public Classe getClasseCourante() {
		return classeCourante;
	}

	public void setClasseCourante(Classe classeCourante) {
		this.classeCourante = classeCourante;
	}

	public boolean isNew() {
		return isNew;
	}

	/*
	 * public static void main(String[] args) { ControleurEleve controler = new
	 * ControleurEleve(null); //dao Pays france = (Pays)
	 * HibernateUtil.getSession
	 * ().createQuery("select p from Pays p where p.codePays = 'FR'"
	 * ).list().get(0); Etablissement etablissement = new Etablissement("nom",
	 * "rue", new VilleDAO(HibernateUtil.getSession()).getVilles().get(0),
	 * "0143565474"); Medecin medecin = new
	 * MedecinDAO(HibernateUtil.getSession()).getMedecins().get(0); try {
	 * controler.editEleve("F11223", "nom", "prenom", "01/01/1980", "75001",
	 * "Paris", france, "h", "rue", "75001", "Paris", france, "email@gmail.com",
	 * "01/09/2011", etablissement, "", "0564756453", "0564756453",
	 * "0564756453", medecin, "ras", "ras", "ras"); controler.validAndQuit(); }
	 * catch (Exception e) { e.printStackTrace(); } } //
	 */
}
